﻿using DotNetty.Transport.Bootstrapping;
using DotNetty.Transport.Channels.Sockets;
using DotNetty.Transport.Channels;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using DotNetty.Codecs;
using DotNetty.Buffers;
using System.Configuration;

[assembly: log4net.Config.XmlConfigurator(Watch = true)]
namespace ShaoLuNettyServer
{
    public class TcpServer
    {
        private static readonly log4net.ILog Logger = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

        private volatile static TcpServer instance = new TcpServer();

        public static TcpServer getInstance()
        {
            return instance;
        }
        private TcpServer()
        {

        }

        private ManualResetEvent _mainThread = new ManualResetEvent(false);

        public void ShutdownGracefully()
        {
            _mainThread.Set();
        }


        public async Task Start()
        {
            /*
            IEventLoopGroup bossGroup = new MultithreadEventLoopGroup(1);
            IEventLoopGroup workerGroup = new MultithreadEventLoopGroup();

            try
            {
                ServerBootstrap bootstrap = new ServerBootstrap()
                    .Group(bossGroup, workerGroup)
                    .Channel<TcpServerSocketChannel>()
                    .Option(ChannelOption.SoBacklog, 100)
                    .ChildHandler(new ActionChannelInitializer<ISocketChannel>(channel =>
                    {
                        IChannelPipeline pipeline = channel.Pipeline;
                        pipeline.AddLast(new LengthFieldBasedFrameDecoder(1024, 0, 4, 0, 4));
                        pipeline.AddLast(new StringDecoder(Encoding.UTF8));
                        pipeline.AddLast(new LengthFieldPrepender(4));
                        pipeline.AddLast(new StringEncoder(Encoding.UTF8));
                        pipeline.AddLast(new TcpServerHandler());
                    }));

                IChannel boundChannel = await bootstrap.BindAsync(7777);
                Console.WriteLine("TCP server started on port 7777. Press any key to exit.");
                Logger.Info("TCP server started on port 7777. Press any key to exit.");
                Console.ReadKey();

                //await boundChannel.CloseAsync();

            }
            finally
            {
                //await Task.WhenAll(
                //    bossGroup.ShutdownGracefullyAsync(TimeSpan.FromMilliseconds(100), TimeSpan.FromSeconds(1)),
                //    workerGroup.ShutdownGracefullyAsync(TimeSpan.FromMilliseconds(100), TimeSpan.FromSeconds(1))
                //);
            }
            */

            int port = 6860;
            string p = ConfigurationManager.AppSettings["NettyPort"];
            if (p == null || "".Equals(p))
            {
                port = int.Parse(p);
            }

            var bossGroup = new MultithreadEventLoopGroup(1);
            var workerGroup = new MultithreadEventLoopGroup();
            try
            {
                var bootstrap = new ServerBootstrap();
                bootstrap
                    .Group(bossGroup, workerGroup) //  
                    .Channel<TcpServerSocketChannel>() // 
                    .Option(ChannelOption.SoBacklog, 100) //  
                    //.Handler(new TcpServerHandler("SRV-LSTN")) // 
                    .ChildHandler(new ActionChannelInitializer<ISocketChannel>(channel =>
                    { // 
                        IChannelPipeline pipeline = channel.Pipeline;

                        IByteBuffer delimiter = Unpooled.Buffer(); ;
                        delimiter.WriteByte((byte)0x7E);
                        pipeline.AddLast(new DelimiterBasedFrameDecoder(1024, delimiter));
                        //pipeline.AddLast(new TcpServerHandler("SRV-CONN"));
                        //pipeline.AddLast("tcpHandler", new ProtocolHandler());
                    }));

                // bootstrap bind port 
                IChannel boundChannel = await bootstrap.BindAsync(port);
                //线程阻塞在这

                _mainThread.WaitOne();
                //关闭服务
                await boundChannel.CloseAsync();
            }
            finally
            {
                await Task.WhenAll(
                    bossGroup.ShutdownGracefullyAsync(TimeSpan.FromMilliseconds(100), TimeSpan.FromSeconds(1)),
                    workerGroup.ShutdownGracefullyAsync(TimeSpan.FromMilliseconds(100), TimeSpan.FromSeconds(1)));
            }

        }
    }
}
